home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 351-375 / disk_351 / pdc / pdcsrc.lzh / A68k / Symtab.c < prev    next >
C/C++ Source or Header  |  1990-04-19  |  38KB  |  1,277 lines

  1. /*------------------------------------------------------------------*/
  2. /*                                    */
  3. /*            MC68000 Cross Assembler                */
  4. /*                                    */
  5. /*        Copyright (c) 1985 by Brian R. Anderson            */
  6. /*                                    */
  7. /*           Symbol table manipulation - November 2, 1989        */
  8. /*                                    */
  9. /*   This program may be copied for personal, non-commercial use    */
  10. /*   only, provided that the above copyright notice is included        */
  11. /*   on all copies of the source code.  Copying for any other use   */
  12. /*   without the consent of the author is prohibited.            */
  13. /*                                    */
  14. /*------------------------------------------------------------------*/
  15. /*                                    */
  16. /*        Originally published (in Modula-2) in            */
  17. /*        Dr. Dobb's Journal, April, May, and June 1986.          */
  18. /*                                    */
  19. /*     AmigaDOS conversion copyright 1989 by Charlie Gibbs.        */
  20. /*                                    */
  21. /*------------------------------------------------------------------*/
  22.  
  23. #include <stdio.h>
  24. #include "A68kdef.h"
  25. #include "A68kglb.h"
  26.  
  27. long Value;    /* Passed from ReadSymTab to CalcValue */
  28.  
  29. /* Functions */
  30. extern int  Instructions(), ObjDir();
  31. extern int  GetInstModeSize(), GetMultReg();
  32. extern int  GetArgs(), GetAReg();
  33. extern long AddrBndW(), AddrBndL();
  34. char *AddName();
  35. struct SymTab *NextSym();
  36. struct SymTab **HashIt();
  37.  
  38. int  OpenIncl(), LineParts(), GetLine(), IsOperator();
  39. int  ReadSymTab(), CountNest();
  40. long GetValue(), CalcValue();
  41. char *GetField();
  42.  
  43.  
  44.  
  45. int OpenIncl (name, dirlist) char *name, *dirlist;
  46. /* Opens the file whose name is in "name".  The current
  47.     directory is tried first.  If that fails, the directory
  48.     names in "dirlist" (separated by commas) are then tried
  49.     until either a file is found or the list is exhausted.
  50.     If the file is found in a subdirectory, "name" is
  51.     modified to include the entire path specification.
  52.     If another input file is open when this routine is called,
  53.     it is closed first.  Returns TRUE if successful, FALSE if not.  */
  54. {
  55.     register char *s, *t;
  56.     char dirname[MAXLINE];
  57.  
  58.     if (In.fd != NULL)
  59.     close (In.fd);        /* Close the inner file. */
  60.  
  61.     if ((In.fd = open (name, 0)) >= 0) {
  62.     In.Ptr = In.Lim = In.Buf;
  63.     if (Quiet < 0)
  64.         fprintf (stderr, "\n%s line ", name);
  65.     return (TRUE);        /* We found it in the current directory. */
  66.     }
  67.     s = dirlist;
  68.     while (*s) {
  69.     s = GetField (s, dirname);
  70.     t = dirname + strlen (dirname) - 1;
  71.     if ((*t != '/') && (*t != ':'))
  72.         strcat (dirname, "/");    /* Slash after directory name */
  73.     strcat (dirname, name);
  74.     if ((In.fd = open (dirname, 0)) >= 0) {
  75.         In.Ptr = In.Lim = In.Buf;
  76.         strcpy (name, dirname);    /* Return entire path. */
  77.         if (Quiet < 0)
  78.         fprintf (stderr, "\n%s line ", name);
  79.         return (TRUE);    /* We found it in a subdirectory. */
  80.     }
  81.     if (*s)
  82.         s++;        /* Skip over separator and try again. */
  83.     }
  84.     In.fd = NULL;
  85.     return (FALSE);        /* We couldn't find it anywhere. */
  86. }
  87.  
  88.  
  89.  
  90. int LineParts (dummy) int dummy;
  91. /* Gets the next statement and extracts its component parts.
  92.     If end of file is reached, and we're in a macro or include
  93.     file, the file is closed and the next outermost file is
  94.     continued.  If we have reached the end of the source file, or
  95.     encounter an ENDM or MEXIT directive within a macro expansion,
  96.     the current input file is closed and TRUE is returned.
  97.  
  98.     If we're in a user macro (indicated by UPtr being nonzero),
  99.     we'll get the next statement from the save area in memory instead.
  100.  
  101.     Macro arguments, if any, are substituted.
  102.  
  103.     LineCount is incremented if a statement was successfully read.
  104.  
  105.     If this is the first call of this routine (i.e. LineCount is zero)
  106.     and HeaderFN is not a null string, we'll return an INCLUDE statement
  107.     requesting the specified header file, rather than reading the first
  108.     statement from the source file.
  109.  
  110.     The following fields are set up:
  111.     Line    - statement line image
  112.     Label    - instruction label (without trailing colon)
  113.     OpCode    - instruction mnemonic (converted to upper case)
  114.     SrcOp    - first (source) operand
  115.     DestOp    - second (destination) operand
  116.     Size    - size from OpCode
  117.     LabLoc    - displacement to start of instruction label
  118.     OpLoc    - displacement to start of instruction mnemonic
  119.     SrcLoc    - displacement to start of source operand
  120.     DestLoc    - displacement to start of destination operand
  121.     InFNum    - decremented if end of file is reached
  122.     InF    - incremented if end of file is reached
  123.     LabLine    - set to LineCount if this line is labeled
  124.             (unless it's a local label)
  125.                                 */
  126. {
  127.     register int i, c;
  128.     int eofflag;
  129.     char *x;
  130.  
  131.  
  132.     while (1) {    /* Repeat until we get something (not end of INCLUDE). */
  133.     Line[0] = Label[0] = OpCode[0] = SrcOp[0] = DestOp[0] = '\0';
  134.     LabLoc = OpLoc = SrcLoc = DestLoc = 0;
  135.     Src.Mode = Dest.Mode = NULL;
  136.     ErrLim = AddrAdv = InstSize = nO = nS = nD = nX = 0;
  137.     PrntAddr = FwdShort = FALSE;
  138.     DupFact = 1;
  139.  
  140.     if ((LineCount==0) && (HeaderFN[0])) {    /* Header file */
  141.         strcpy (Line, "        INCLUDE ");    /* Make an INCLUDE stmt. */
  142.         strcat (Line, HeaderFN);
  143.         strcat (Line, "        ;Generated for header file");
  144.         strcpy (OpCode, "INCLUDE");    /* Dummy op code */
  145.         OpLoc = 8;
  146.         strcpy (SrcOp, HeaderFN);    /* Dummy source operand */
  147.         SrcLoc = 16;
  148.         LineCount++;
  149.         return (FALSE);
  150.     }
  151.  
  152.     if (InF->UPtr != 0) {            /* User macro input */
  153.         GetMacLine (dummy);
  154.         eofflag = FALSE;
  155.     } else {                /* Normal file input */
  156.         eofflag = GetLine (dummy);
  157.     }
  158.     if ((Line[0] != '\0') && (Line[0] != '*') && (Line[0] != ';')) {
  159.         SubArgs (dummy);    /* Substitute macro arguments. */
  160.         GetParts (dummy);    /* Break Line into its component parts. */
  161.     }
  162.  
  163.     /* ------ If we have reached the end of a macro or ------ */
  164.     /* ------ include file, return to the calling file. ----- */
  165.  
  166.     i = eofflag;                /* End of file */
  167.  
  168.     if (i) {
  169.         if (SkipNest != 0) {
  170.         Error (OpLoc, NoENDC);    /* ENDC is missing! */
  171.         WriteListLine (&List);    /* It's not normally listed. */
  172.         SkipNest = 0;
  173.         }
  174.     } else if ((InF->NArg != -1)&&(Dir != Macro)) {    /* Macro exits */
  175.         if (strcmp (OpCode, "ENDM") == 0) {
  176.         i = TRUE;
  177.         (InF->Line)++;        /* Count ENDM directive. */
  178.         if (SkipNest != 0) {
  179.             Error (OpLoc, NoENDC);  /* ENDC is missing! */
  180.             WriteListLine (&List);  /* It's not normally listed. */
  181.             SkipNest = 0;
  182.         }
  183.         } else if (SkipNest == 0) {
  184.         if (strcmp (OpCode, "MEXIT") == 0) {
  185.             i = TRUE;
  186.             (InF->Line)++;    /* Count MEXIT directive. */
  187.         }
  188.         }
  189.     }
  190.     if (!i) {            /* Not end of file or macro */
  191.         if (PrevDir == MacCall) {
  192.         if (strcmp (OpCode, "MACRO") == 0) {
  193.             (InF->Line)++;    /* Count macro header */
  194.             continue;        /*  and ignore it.    */
  195.         }
  196.         }
  197.         if (SkipNest == 0) {    /* If we're not skipping, */
  198.         break;            /*  we got something.     */
  199.         } else {
  200.         (InF->Line)++;        /* Count skipped lines. */
  201.         SkipNest += CountNest (OpCode);    /* Adjust SkipNest. */
  202.         continue;
  203.         }
  204.     }
  205.     if (!Pass2 && (IncStart != 0) && (IncPtr == InF)) {
  206.         SkipLim->Start = IncStart;    /* End of skippable INCLUDE */
  207.         SkipLim->Finish=LineCount;    /* Save line numbers for pass 2. */
  208.         SkipLim->MCount = MacCount;    /* Save macro counter too. */
  209.         if (SkipLim->Set1 != NULL) {
  210.         SetFixLim--;
  211.         x = (char *) SkipLim + sizeof (struct SkipEnt);
  212.         if (x > (char *) SetFixLim) {
  213.             SetFixLim++;    /* No room for final entry */
  214.         } else {
  215.             SetFixLim->Sym  = NULL;    /* Null entry        */
  216.             SetFixLim->Val  = 0;    /*  indicates end of */
  217.             SetFixLim->Hunk = 0;    /*  SET symbol list. */
  218.         }
  219.         }
  220.         SkipLim++;
  221.         IncStart = 0;
  222.     }
  223.     if (InFNum == 0)
  224.         break;            /* End of source file */
  225.     if (i = (InF->UPtr == 0)) {
  226.         if (Quiet < 0)
  227.         fprintf (stderr, "%d\n", InF->Line);
  228.         close (In.fd);        /* Close inner file. */
  229.         In.fd = NULL;
  230.     }
  231.     NextFNS = InF->NPtr;        /* Release space on name stack. */
  232.     InFNum--;            /* Return to outer file. */
  233.     InF++;
  234.     if (InFNum < OuterMac)
  235.         OuterMac = 0;        /* End of outer macro */
  236.     if (InF->UPtr == 0) {
  237.         if (i)
  238.         ShowFile (FALSE);    /* Inner file -> outer file */
  239.         else if (InnrFMac) {
  240.         ShowFile (FALSE);    /* Inner user macro -> file */
  241.         InnrFMac = FALSE;
  242.         }
  243.         if (In.fd == NULL) {
  244.         In.fd = open (InF->NPtr, 0);
  245.         lseek (In.fd, InF->Pos, 0);
  246.         In.Ptr = In.Lim = In.Buf;
  247.         }
  248.     } else if (i) {
  249.         InnrFMac = TRUE;    /* Inner file -> outer user macro */
  250.     }
  251.     }
  252.     LineCount++;            /* Bump line counter. */
  253.     (InF->Line)++;
  254.     if ((Label[0] != '\0') && (Label[0] != '\\'))
  255.     if ((Label[0] < '0') || (Label[0] > '9'))
  256.         LabLine = LineCount;    /* Save line number of label. */
  257.     if (Quiet != 0) {
  258.     i = (Quiet < 0 ? InF->Line : LineCount);
  259.     if ((i % Quiet) == 0) {        /* Display progress. */
  260.         ShowLine (i);
  261.     }
  262.     }
  263.  
  264.     if (LineCount == DebugStart)
  265.     fprintf (stderr, "%d\n", LineCount);
  266.     if ((LineCount >= DebugStart) && (LineCount <= DebugEnd))
  267.     printf ("%9lx %5d %s\n", AddrCnt, LineCount, Line);
  268.  
  269.     return (eofflag);
  270. }
  271.  
  272.  
  273.  
  274. GetMacLine (dummy) int dummy;
  275. /* Gets the next stored user macro line. */
  276. {
  277.     register char *s, *t;
  278.     register struct NameChunk *np;
  279.  
  280.     s = InF->UPtr;
  281.     if (*s == '\n') {        /* Continue in next chunk. */
  282.     np = NameStart;
  283.     while ((s < (char *) np)
  284.     || (s > ((char *) np + CHUNKSIZE)))
  285.         np = np->Link;    /* Find the chunk we're in. */
  286.     InF->UPtr = (char *) (np->Link) + sizeof (struct NameChunk *);
  287.     s = InF->UPtr;
  288.     }
  289.     t = Line;
  290.     while (*t++ = *s++)    /* Copy InF->UPtr to Line, then bump InF->UPtr. */
  291.     ;        /*  (It's faster than doing a strcpy followed   */
  292.     InF->UPtr = s;    /*  by a strlen to bump the pointer.)           */
  293. }
  294.  
  295.  
  296.  
  297. int GetLine (dummy) int dummy;
  298. /* Gets the next line from the current input file and leaves it in Line.
  299.     Returns TRUE if end of file has been reached, FALSE otherwise.    */
  300. {
  301.     register char *s;
  302.     register int c;
  303.     register char *t, *m, *l;
  304.  
  305.     s = Line;
  306.     t = In.Ptr;                /* Use a register for speed. */
  307.     m = Line + MAXLINE - 1;        /* Limit of "Line" */
  308.     while (1) {                /* Get Line, expanding tabs. */
  309.     if (t >= In.Lim) {
  310.         t = In.Buf;            /* Re-fill the buffer. */
  311.         In.Lim = In.Buf + read (In.fd, In.Buf, BUFFSIZE);
  312.         if (In.Lim == In.Buf) {
  313.         *s = '\0';        /* End of file */
  314.         In.Ptr = t;
  315.         return (s <= Line);    /* Last line might have no \n. */
  316.         }
  317.     }
  318.     if ((c = *t++) == '\n') {
  319.         break;
  320.     }
  321. #ifdef MSDOS
  322.     if (c == 26) {
  323.         *s = '\0';            /* Catch MS-DOS EOF char. */
  324.         In.Ptr = t;
  325.         return (s <= Line);
  326.     }
  327.     if ((s < m) && (c != 13)) {    /* Ignore excess. */
  328. #else
  329.     if (s < m) {            /* Ignore excess. */
  330. #endif
  331.         if ((c == '\t') && !KeepTabs) {
  332.         l = Line + (((s - Line) + 8) & ~7);
  333.         if (l > m)
  334.             l = m;        /* We tabbed off the end. */
  335.         while (s < l)
  336.             *s++ = ' ';        /* Expand tabs. */
  337.         } else {
  338.         *s++ = c;        /* Normal character */
  339.         }
  340.     }
  341.     }
  342.     *s = '\0';            /* Terminate the string in Line. */
  343.     In.Ptr = t;
  344.     return (FALSE);
  345. }
  346.  
  347.  
  348.  
  349. SubArgs (dummy) int dummy;
  350. /* Macro argument substitution routine */
  351. {
  352.     int j;
  353.     register char *s, *t, *x;
  354.     char subline[MAXLINE];
  355.  
  356.     if (InF->NArg == -1)
  357.     return;            /* Not a macro - leave Line alone. */
  358.  
  359.     s = Line;
  360.     t = subline;
  361.     while (*s) {
  362.     if ((*t++ = *s++) != '\\') {
  363.         continue;
  364.     }
  365.     x = s--;
  366.     t--;
  367.     if (*x == '@') {    /* \@ - substitute macro number. */
  368.         x = t;
  369.         *t++ = '.';
  370.         j = InF->MCnt % 1000;
  371.         *t++ = j / 100 + '0';
  372.         j = j % 100;
  373.         *t++ = j / 10 + '0';
  374.         *t++ = j % 10 + '0';
  375.         strcpy (t, s+2);        /* Remainder of Line */
  376.         strcpy (Line, subline);    /* Replace Line. */
  377.         while (*t != '\\')        /* Check for more substitutions. */
  378.         if (*t)
  379.             t++;
  380.         else
  381.             return;        /* All done */
  382.         s = t - subline + Line;    /* Do the next substitution. */
  383.         continue;
  384.     }
  385.     if ((*x < '0') || (*x > '9')) {
  386.         s++;        /* False alarm - it's a   */
  387.         t++;        /*  named local variable. */
  388.         continue;
  389.     }
  390.  
  391.     s++;
  392.     *t = '\0';
  393.     j = 0;            /* Get argument index. */
  394.     while ((*s >= '0') && (*s <= '9')) {
  395.         j *= 10;
  396.         j += *s++ - '0';    /* Current digit */
  397.     }
  398.     if (j == 0)
  399.         strcpy (t, MacSize);    /* Macro call size */
  400.     else if ((j > 0) && (j <= InF->NArg)) {
  401.         x = InF->NPtr;
  402.         while (j > 0) {        /* Find argument. */
  403.         x += strlen (x) + 1;
  404.         j--;
  405.         }
  406.         strcpy (t, x);        /* Insert it. */
  407.     }
  408.     while (*t)
  409.         t++;            /* Skip over replacement. */
  410.     strcpy (t, s);            /* Remainder of Line */
  411.     strcpy (Line, subline);        /* Replace Line. */
  412.     while (*t != '\\')        /* Check for more substitutions. */
  413.         if (*t)
  414.         t++;
  415.         else
  416.         return;            /* All done */
  417.     s = t - subline + Line;        /* Do the next substitution. */
  418.     }
  419. }
  420.  
  421.  
  422.  
  423. GetParts (dummy) int dummy;
  424. /* Break up Line into its component parts. */
  425. {
  426.     register char *s, *x;
  427.  
  428.     Size = S0;
  429.     s = Line;
  430.     if (!isspace (*s)) {
  431.     x = Label;
  432.     while (!isspace (*s) && (*s != ';') && (*s != '\0'))
  433.         *x++ = *s++;        /* Get the label. */
  434.     *x-- = '\0';
  435.     while (*x == ':') {
  436.         *x-- = '\0';        /* Strip trailing colon(s). */
  437.         if (x < Label)
  438.         break;
  439.     }
  440.     }
  441.     while (OpLoc == 0) {
  442.     while (isspace (*s))
  443.         s++;            /* Skip over to opcode. */
  444.     if ((*s == ';') || (*s == '\0'))
  445.         return;            /* End of statement image */
  446.     OpLoc = s - Line;
  447.     x = OpCode;
  448.     while (!isspace (*s) && (*s != ';') && (*s != '\0'))
  449.         *x++ = *s++;        /* Get the opcode. */
  450.     *x-- = '\0';
  451.     if (*x == ':') {        /* It's actually a label. */
  452.         if (Label[0]) {
  453.         Error (OpLoc, MultLab);    /* Multiple labels */
  454.         } else {
  455.         while ((x >= OpCode) && (*x == ':'))
  456.             *x-- = '\0';
  457.         strcpy (Label, OpCode);    /* Get the label. */
  458.         }
  459.         OpLoc = 0;            /* Try again for opcode. */
  460.         OpCode[0] = '\0';
  461.     }
  462.     }
  463.     for (x = OpCode; *x; x++)        /* Convert OpCode  */
  464.     *x = toupper(*x);        /*  to upper case. */
  465.     x -= 2;
  466.     if ((x < OpCode) || (*x != '.'))    /* If no explicit size is given */
  467.     Size = Word;            /*  default to Word (16 bits).  */
  468.     else {
  469.     *x++ = '\0';            /* Chop off size extension. */
  470.     switch (*x) {
  471.     case 'B':            /* Byte */
  472.     case 'S':            /* Short Branch */
  473.         Size = Byte;
  474.         break;
  475.     case 'W':            /* Word */
  476.         Size = Word;
  477.         break;
  478.     case 'L':            /* Long */
  479.         Size = Long;
  480.         break;
  481.     default:
  482.         Error (OpLoc+x-OpCode, SizeErr);    /* Invalid size */
  483.         Size = Word;            /* Default to Word. */
  484.         break;
  485.     }
  486.     }
  487.     while (isspace(*s))
  488.     s++;                /* Skip over to operands. */
  489.     if ((*s == ';') || (*s == '\0'))
  490.     return;                /* There are no operands. */
  491.     SrcLoc = s - Line;
  492.     s = GetField (s, SrcOp);        /* Op1 (source) */
  493.     if (*s == ',')
  494.     s++;
  495.     if (!isspace (*s) && (*s != '\0') && (*s != ';')) {
  496.     DestLoc = s - Line;
  497.     s = GetField (s, DestOp);    /* Op2 (destination) */
  498.     }
  499. }
  500.  
  501.  
  502.  
  503. ShowFile (newline) int newline;
  504. /* Shows the current file name if we're displaying all input modules.
  505.     If "newline" is TRUE, go to a new line before displaying the name. */
  506. {
  507.     if ((Quiet < 0) && (InF->UPtr == 0))
  508.     if (newline)
  509.         fprintf (stderr, "\n%s line ", InF->NPtr);
  510.     else
  511.         fprintf (stderr, "%s line ", InF->NPtr);
  512. }
  513.  
  514.  
  515.  
  516. ShowLine (i) register int i;
  517. /* Shows the current line number and backs up over it. */
  518. {
  519.     if (i >= 10000)
  520.     fprintf (stderr, "%5d\b\b\b\b\b", i);
  521.     else if (i >= 1000)
  522.     fprintf (stderr, "%4d\b\b\b\b", i);
  523.     else if (i >= 100)
  524.     fprintf (stderr, "%3d\b\b\b", i);
  525.     else if (i >= 10)
  526.     fprintf (stderr, "%2d\b\b", i);
  527.     else
  528.     fprintf (stderr, "%1d\b", i);
  529.     fflush (stderr);        /* Make sure it gets out. */
  530. }
  531.  
  532.  
  533.  
  534. char *GetField (s, d) register char *s, *d;
  535. /* Gets a field from "s", returns result in "d".
  536.     Stops on the first comma, semicolon, or white space not
  537.     enclosed within apostrophes or parentheses.
  538.     Returns stopping location.
  539.     If already at end of "s", "d" is set to null string. */
  540. {
  541.     register char c;
  542.     register int parncnt, instring;
  543.  
  544.     instring = FALSE;
  545.     parncnt = 0;
  546.  
  547.     while (c = *s) {
  548.     if (instring) {
  549.         *d++ = c;
  550.     } else {
  551.         if (isspace(c) || (c == ';'))
  552.         break;
  553.         else if ((c == ',') && (parncnt == 0))
  554.         break;
  555.         else {
  556.         *d++ = c;
  557.         if (c == '(')
  558.             parncnt++;
  559.         else if (c == ')')
  560.             parncnt--;
  561.         }
  562.     }
  563.     if (c == '\'')
  564.         instring = !instring;
  565.     s++;
  566.     }
  567.     *d = '\0';
  568.     return (s);
  569. }
  570.  
  571.  
  572.  
  573. long GetValue (operand, loc) char *operand; int loc;
  574. /* Determines value of expression. */
  575. /* Hunk2 is set to hunk number of result (ABSHUNK if absolute).
  576.    If the expression consists solely of self-defining terms,
  577.     DefLine2 is set to zero.  Otherwise, DefLine2 is set
  578.     to the highest statement number in which any symbol in
  579.     the expression was defined.  If the expression contains
  580.     any undefined symbols, DefLine2 is set to NODEF.
  581.     SingleFlag is set to TRUE if the expression consists of a
  582.     single term, FALSE otherwise.
  583.     The following code is based on a regular-to-Polish expression
  584.     converter described in "A Guide to FORTRAN IV Programming"
  585.     by Daniel D. McCracken (John Wiley & Sons, Inc. 1965,
  586.     3rd printing August 1968).  However, rather than generating
  587.     the entire Polish expression, this routine will evaluate
  588.     and combine two terms as soon as an operator of lower
  589.     precedence is encountered.                */
  590. {
  591.     register char *o, *s;
  592.     char tempop[MAXLINE];
  593.     int  oloc, parncnt, nextprec, instring;
  594.     long templong;
  595.     struct TermStack *origterm;
  596.  
  597.     instring = (unsigned int) '~';
  598.     OpPrec[instring] = 9;    /* Fudge IsOperator for speed. */
  599.     SingleFlag = TRUE;        /* Assume there's only a single term. */
  600.     for (o = operand; *o; o++) {
  601.     if (IsOperator (o)) {
  602.         SingleFlag = FALSE;    /* It's not a single term. */
  603.         break;
  604.     }
  605.     }
  606.     instring = (unsigned int) '~';
  607.     OpPrec[instring] = '\0';    /* Restore IsOperator. */
  608.     if (SingleFlag)
  609.     return(CalcValue(operand,loc));    /* Short cut for single term */
  610.  
  611.     Hunk2 = ABSHUNK;
  612.     parncnt = DefLine2 = 0;
  613.     o = (char *) (((long) NextFNS + 3L) & ~3L);
  614.     origterm = Term = (struct TermStack *) o;    /* Term stack */
  615.     Ops = (struct OpStack *) InF;        /* Operator stack */
  616.     Ops--;
  617.     ParseSpace (0);
  618.     Ops->chr = ' ';        /* Prime the operator stack. */
  619.     Ops->prec = -1;
  620.     if ((char *) Ops < Low2)
  621.     Low2 = (char *) Ops;
  622.  
  623.     /* Get all tokens.
  624.     Terms are evaluated, and operator precedence is determined.
  625.     Left and right parentheses are given a precedence of
  626.         1 and 2 respectively.
  627.     Binary operators are given precedence values starting at 3.
  628.     Unary plus is ignored.
  629.     Unary minus is converted to zero minus the remainder of
  630.         of the expression - its precedence is set to 9 to
  631.         ensure that the simulated unary operator is evaluated
  632.         before the remainder of the expression.
  633.     Logical not (~), being another unary operator, is converted
  634.         to -1 exclusive-ORed with the remainder of the expression.
  635.         Its precedence is also set to 9.                */
  636.  
  637.     o = operand;            /* Current position in operand */
  638.  
  639.     while (1) {
  640.     while (*o == '(') {        /* Left parenthesis */
  641.         Ops--;
  642.         ParseSpace (0);
  643.         Ops->chr  = '(';
  644.         Ops->prec = 1;
  645.         if ((char *) Ops < Low2)
  646.         Low2 = (char *) Ops;
  647.         parncnt++;
  648.         o++;
  649.     }
  650.     if ((*o == '+') || (*o == '-') || (*o == '~')) {    /* Unary op */
  651.         if (*o != '+') {    /* Ignore unary plus. */
  652.         Ops--;
  653.         ParseSpace (sizeof (struct TermStack));
  654.         Term->value   = (*o == '-') ? 0 : -1;    /* Dummy value */
  655.         Term->hunk    = ABSHUNK;
  656.         Term->oploc   = loc + (o - operand);
  657.         Term->defline = 0;
  658.         Term++;
  659.         if ((char *) Term > High2)
  660.             High2 = (char *) Term;
  661.         Ops->chr  = *o;        /* Now get the operator itself. */
  662.         Ops->prec = 9;        /* Do it ASAP. */
  663.         if ((char *) Ops < Low2)
  664.             Low2 = (char *) Ops;
  665.         }
  666.         o++;
  667.         if (*o == '(')
  668.         continue;    /* Inner parenthesized expression */
  669.     }
  670.     oloc = loc + (o - operand);
  671.  
  672.     s = tempop;                /* Get a term. */
  673.     if (*o == '*') {    /* It's a location counter reference, */
  674.         *s++ = *o++;    /*   not a multiplication operator!   */
  675.     } else {
  676.         if (IsOperator (o) || (*o == '\0')) {
  677.         Error (oloc, OperErr);    /* Unexpected operator or no terms */
  678.         return (0L);
  679.         }
  680.         instring = (unsigned int) '~';
  681.         OpPrec[instring] = 9;    /* Fudge IsOperator for speed. */
  682.         instring = FALSE;
  683.         while (*o) {
  684.         if (*o == '\'')
  685.             instring=!instring;    /* String delimiter */
  686.         if (!instring && IsOperator (o))
  687.             break;        /* Found an operator - stop. */
  688.         *s++ = *o++;        /* Get a character. */
  689.         }
  690.         instring = (unsigned int) '~';
  691.         OpPrec[instring] = '\0';    /* Restore IsOperator. */
  692.     }
  693.     *s = '\0';
  694.     ParseSpace (sizeof (struct TermStack));
  695.     Term->value   = CalcValue (tempop, oloc);
  696.     Term->hunk    = Hunk2;
  697.     Term->oploc   = oloc;
  698.     Term->defline = DefLine2;
  699.     Term++;
  700.     if ((char *) Term > High2)
  701.         High2 = (char *) Term;
  702.     Hunk2 = DefLine2 = 0;
  703.  
  704.     while (*o == ')') {        /* Right parenthesis */
  705.         if (parncnt == 0) {
  706.         Error ((int) (loc + (o - operand)), OperErr);
  707.         return (0L);
  708.         }
  709.         CondCalc (2);        /* Unstack what we can. */
  710.         if (Ops->chr == '(')
  711.         Ops++;            /* Drop paired parentheses. */
  712.         else {
  713.         Ops--;
  714.         ParseSpace (0);
  715.         Ops->chr  = ')';    /* Stack parenthesis for now. */
  716.         Ops->prec = 2;
  717.         if ((char *) Ops < Low2)
  718.             Low2 = (char *) Ops;
  719.         }
  720.         parncnt--;
  721.         o++;
  722.     }
  723.     if (*o) {
  724.         nextprec = IsOperator (o);
  725.         if ((nextprec == 0) || (*o == '(')) {
  726.         Error ((int) (loc + (o - operand)), OperErr);
  727.         return (0L);        /* We expected an operator. */
  728.         }
  729.         CondCalc (nextprec);    /* Unstack what we can. */
  730.         Ops--;
  731.         ParseSpace (0);
  732.         Ops->chr  = *o;        /* Stack the next operator. */
  733.         Ops->prec = nextprec;
  734.         if ((char *) Ops < Low2)
  735.         Low2 = (char *) Ops;
  736.         if ((*o == '<') || (*o == '>'))
  737.         o++;    /* Skip over two-character operator. */
  738.         o++;
  739.     } else {
  740.         if (parncnt) {
  741.         Error ((int) (loc + (o - operand)), OperErr);
  742.         return (0L);    /* Too many left parentheses */
  743.         }
  744.         CondCalc (0);        /* Unstack what's left. */
  745.         if (--Term != origterm)    /* Should be only one term left */
  746.         Error (Term->oploc, OperErr);        /* Parser bug? */
  747.         Hunk2    = Term->hunk;
  748.         DefLine2 = Term->defline;
  749.         return (Term->value);    /* Final value */
  750.     }
  751.     }
  752. }
  753.  
  754.  
  755.  
  756. CondCalc (newprec) int newprec;
  757. /* As long as the top operator on the operator stack has a precedence
  758.     greater than or equal to the contents of "newprec", this routine
  759.     will pop the two top terms from the term stack, combine them
  760.     according to the operator on the top of the operator stack (which
  761.     is also popped), and push the result back onto the term stack. */
  762. {
  763.     while (Ops->prec >= newprec) {    /* Unstack an operator. */
  764.     Term -= 2;
  765.     if (Ops->chr == '+') {        /* Relocatable addition */
  766.         if (Term->hunk == ABSHUNK)
  767.         Term->hunk = (Term+1)->hunk;    /* A+R */
  768.         else if ((Term+1)->hunk != ABSHUNK) {
  769.         Error ((Term+1)->oploc,RelErr);    /* R+R - error */
  770.         Term->hunk = ABSHUNK;        /* Make it absolute. */
  771.         }
  772.     } else if (Ops->chr == '-') {        /* Subtraction */
  773.         if (Term->hunk == (Term+1)->hunk)
  774.         Term->hunk = ABSHUNK;        /* R-R - absolute */
  775.         else if ((Term+1)->hunk != ABSHUNK) {   /* R-R across hunks  */
  776.         Error ((Term+1)->oploc, RelErr);    /*  is an error -    */
  777.         Term->hunk = ABSHUNK;            /* make it absolute. */
  778.         }
  779.     } else if ((Term->hunk != ABSHUNK)
  780.     || ((Term+1)->hunk != ABSHUNK)) {
  781.         Error (Term->oploc,RelErr);        /* All other operations */
  782.         Term->hunk = ABSHUNK;        /*   must be absolute.  */
  783.     }
  784.     if ((Term+1)->defline > Term->defline)    /* Definition */
  785.         Term->defline = (Term+1)->defline;    /*  line nos. */
  786.  
  787.     switch (Ops->chr) {        /* Perform the operation. */
  788.     case '+':
  789.         Term->value += (Term+1)->value;
  790.         break;
  791.     case '-':
  792.         Term->value -= (Term+1)->value;
  793.         break;
  794.     case '*':
  795.         Term->value *= (Term+1)->value;
  796.         break;
  797.     case '/':
  798.         if ((Term+1)->value)
  799.         Term->value /= (Term+1)->value;
  800.         else
  801.         Term->value = 0;    /* Don't divide by zero. */
  802.         break;
  803.     case '&':
  804.         Term->value &= (Term+1)->value;
  805.         break;
  806.     case '!':
  807.     case '|':
  808.         Term->value |= (Term+1)->value;
  809.         break;
  810.     case '<':
  811.         Term->value <<= (Term+1)->value;
  812.         break;
  813.     case '>':
  814.         Term->value >>= (Term+1)->value;
  815.         break;
  816.     case '~':
  817.         Term->value ^= (Term+1)->value;
  818.         break;
  819.     default:
  820.         Error (Term->oploc, OperErr);    /* Parser bug? */
  821.         break;
  822.     }
  823.     Term++;
  824.     Ops++;
  825.     }
  826. }
  827.  
  828.  
  829.  
  830. int IsOperator (o) register char *o;
  831. /* Tests whether "o" points to a valid operator or parenthesis.
  832.     Returns the precedence of the operator, or 0 if it isn't one. */
  833. {
  834.     register unsigned int i;
  835.  
  836.     i = (unsigned int) *o;
  837.     i = (unsigned int) OpPrec[i];
  838.     if (i != 6)
  839.     return ((int) i);
  840.     if (*(o+1) == *o)
  841.     return ((int) i);    /* << or >> */
  842.     else
  843.     return (0);        /* False alarm */
  844. }
  845.  
  846.  
  847.  
  848. long CalcValue (operand, loc) char *operand; int loc;
  849. /* Evaluates a single term (called by GetValue).
  850.     Hunk2 receives relative hunk number (ABSHUNK if absolute).
  851.     If the value is a symbol, DefLine2 is set to the line number
  852.     where it was defined, or NODEF if it is undefined.
  853.     For self-defining terms, DefLine2 is set to zero.    */
  854. {
  855.     register long result;    /* Result is calculated here. */
  856.     register char *s, *numstart;
  857.     register int  radix;
  858.     int  neg, overflow;
  859.     long templong;
  860.     char maxdig;    /* Highest valid digit in current radix */
  861.     char delim;        /* String delimiter (' or ") */
  862.  
  863.     Hunk2 = ABSHUNK;            /* Assume value is absolute */
  864.     DefLine2 = 0;            /*  and self-defining.      */
  865.     result = 0;
  866.     overflow = FALSE;
  867.     if (neg = (*operand == '-'))
  868.     numstart = operand + 1;        /* Negative value */
  869.     else
  870.     numstart = operand;        /* Positive value */
  871.  
  872.     if ((*numstart >= '0') && (*numstart <= '9')) {
  873.     radix = 10;        /* Decimal number */
  874.     maxdig = '9';
  875.     } else if (*numstart == '$') {
  876.     radix = 16;        /* Hexadecimal number */
  877.     maxdig = '9';
  878.     } else if (*numstart == '@') {
  879.     radix = 8;        /* Octal number */
  880.     maxdig = '7';
  881.     } else if (*numstart == '%') {
  882.     radix = 2;        /* Binary number */
  883.     maxdig = '1';
  884.     } else
  885.     radix = 0;        /* Not a number */
  886.  
  887.     if (radix != 0) {            /* Some sort of number */
  888.     result = 0;
  889.     if (radix != 10)
  890.         numstart++;            /* Allow for type character. */
  891.     for (s = numstart; *s; s++) {
  892.         if (result > 0xFFFFFFFL) {
  893.         templong = result * radix;
  894.         if (((templong / radix) != result) && !overflow) {
  895.             Error (loc, SizeErr);    /* Won't fit into a long word! */
  896.             overflow = TRUE;
  897.         }
  898.         }
  899.         result *= radix;
  900.         if ((*s >= '0') && (*s <= maxdig)) {
  901.         result += (*s - '0');
  902.         } else if (radix == 16) {
  903.         if ((*s >= 'A') && (*s <= 'F'))
  904.             result += (*s - 'A' + 10);
  905.         else if ((*s >= 'a') && (*s <= 'f'))
  906.             result += (*s - 'a' + 10);
  907.         else
  908.             Error (loc + s - operand, OperErr);
  909.         } else if (!neg && (radix==10) && (*s=='$') && (*(s+1)=='\0')) {
  910.         if (ReadSymTab (operand)) {    /* Look up local label. */
  911.             result = Value;        /* Get its value. */
  912.             AddRef (LineCount);        /* Add reference. */
  913.             if (Sym->Flags & 0x60)
  914.             Error (loc, AddrErr);    /* Can't use a register equate! */
  915.         } else {
  916.             Error (loc, Undef);        /* Undefined */
  917.         }
  918.         break;
  919.         } else {
  920.         Error (loc + s - operand, OperErr);
  921.         }
  922.     }
  923.     } else if ((*operand == '\'') || (*operand == '"')) {
  924.     delim = *operand;        /* Character value delimiter */
  925.     result = 0;
  926.     s = operand + 1;
  927.     while (1) {
  928.         if (*s == '\0') {
  929.         Error (loc+s-operand,NoStrEnd);    /* End is missing! */
  930.         result = 0;
  931.         break;
  932.         }
  933.         if (*s == delim) {        /* End of string? */
  934.         if (*(++s) != delim)    /* Check next character. */
  935.             break;        /* End of string */
  936.         }        /* Otherwise it's an apostrophe in the string. */
  937.         if ((result & 0xFF000000L) && !overflow) {
  938.         Error (loc+s-operand, SizeErr);    /* Result overflowed! */
  939.         overflow = TRUE;
  940.         result = 0;
  941.         }
  942.         if (!overflow)
  943.         result = (result << 8) + *s;
  944.         s++;
  945.     }
  946.     } else if ((*operand == '*') && (*(operand+1) == '\0')) {
  947.     result = AddrCnt;    /* Value of location counter */
  948.     Hunk2 = CurrHunk;    /* Use current section's hunk number. */
  949.     } else {
  950.     if (ReadSymTab (operand)) {    /* Look up symbol. */
  951.         result = Value;        /* Get its value. */
  952.         AddRef (LineCount);        /* Add reference. */
  953.         if (Pass2 && (Sym->Defn == NODEF))
  954.         Error (loc, Undef);
  955.         else if (Sym->Flags & 0x60)
  956.         Error (loc, AddrErr);    /* Can't use a register equate! */
  957.     } else if (strcmp (operand, "NARG") == 0) {
  958.         result = InF->NArg;        /* Number of arguments */
  959.         if (result == -1)
  960.         result = 0;        /* No arguments outside macros */
  961.     } else
  962.         Error (loc, Undef);        /* Undefined */
  963.     }
  964.     if (neg) {
  965.     result = -result;        /* Negative value */
  966.     if (Hunk2 != ABSHUNK)
  967.         Error (loc, RelErr);    /* Must be absolute! */
  968.     }
  969.     return (result);
  970. }
  971.  
  972.  
  973.  
  974. AddSymTab (label, value, hunk, line, flags)
  975. char label[];
  976. long value, hunk;
  977. int line, flags;
  978. /* Inserts a new entry to the symbol table and increments NumSyms.
  979.     "Sym" will be set to point to the new entry.
  980.     If the label is a local label (i.e. the first character is
  981.     a numeric digit or a backslash), the current contents of LabLine
  982.     will be converted to characters and appended to the label before
  983.     it is added.  If the first character of the label is a backslash
  984.     (i.e. a named local variable) a dollar sign will be appended
  985.     to the label ahead of the value of LabLine.            */
  986. {
  987.     char wlab[MAXLINE], wnum[6];
  988.     register struct SymTab *chainsym, **hashindex;
  989.  
  990.     strcpy (wlab, label);
  991.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  992.     if (label[0] == '\\')
  993.         strcat (wlab, "$");
  994.     sprintf (wnum, "%d", LabLine);    /* If it's a local label, */
  995.     strcat (wlab, wnum);        /*    append LabLine.     */
  996.     }
  997.  
  998.     Sym = SymLim;            /* Pointer to new entry */
  999.     SymLim++;                /* Bump limit pointer. */
  1000.     if (((char *) SymLim - (char *) SymCurr) > CHUNKSIZE) {
  1001.     Sym = (struct SymTab *) malloc ((unsigned) CHUNKSIZE);
  1002.     if (Sym == NULL)
  1003.         quit_cleanup ("Out of memory!\n");
  1004.     SymCurr->Link = Sym;        /* Link from previous chunk */
  1005.     SymCurr = Sym;            /* Make the new chunk current. */
  1006.     SymCurr->Link = NULL;        /* Clear forward pointer. */
  1007.     Sym++;                /* Skip over pointer entry. */
  1008.     SymLim = Sym;            /* New table limit */
  1009.     SymLim++;            /* Bump it. */
  1010.     }
  1011.     Sym->Link = NULL;        /* Clear hash chain link. */
  1012.     Sym->Nam = AddName(wlab,0);    /* Pointer to symbol */
  1013.     Sym->Val   = value;        /* Value */
  1014.     Sym->Hunk  = hunk;        /* Hunk number */
  1015.     Sym->Defn  = line;        /* Statement number */
  1016.     Sym->Flags = flags;        /* Flags */
  1017.     Sym->Ref1  = NULL;        /* Reference pointer */
  1018.     NumSyms++;            /* Count symbols. */
  1019.  
  1020.     hashindex = HashIt (wlab);    /* Get hash index. */
  1021.     if (*hashindex == NULL) {
  1022.     *hashindex = Sym;    /* First entry in this hash chain */
  1023.     return;
  1024.     }
  1025.     chainsym = *hashindex;
  1026.     while (chainsym->Link != NULL)
  1027.     chainsym = chainsym->Link;    /* Scan for end of hash chain. */
  1028.     chainsym->Link = Sym;        /* Insert new entry at the end. */
  1029. }
  1030.  
  1031.  
  1032.  
  1033. char *AddName (name, macflag) char *name; int macflag;
  1034. /* Adds the name in "name" to the name heap.
  1035.     "macflag" can take any of the following values:
  1036.     0 - normal name
  1037.     1 - first line of macro text - there must be room on the
  1038.         name heap for at least one character following "name".
  1039.     2 - additional lines of macro text - make sure there's room
  1040.         for an addition character (as in 1 above).  Also,
  1041.         if it is necessary to allocate a new chunk of memory,
  1042.         first place a newline character after the last entry
  1043.         in the old chunk.  This acts as a flag when retrieving
  1044.         lines of macro text during an expansion.
  1045.     This function returns a pointer to "name" on the name heap. */
  1046. {
  1047.     register char *s, *t;
  1048.     struct NameChunk *n;
  1049.  
  1050.     s = NameLim + strlen(name) + 1;    /* The new entry ends here. */
  1051.     if (macflag)            /* If this is a macro, */
  1052.     s++;                /*  allow for continuation flag. */
  1053.     if ((s - (char *) NameCurr) > CHUNKSIZE) {    /* If this chunk is full */
  1054.     if (macflag == 2)        /* If this is more macro text */
  1055.         *NameLim = '\n';        /*  insert continuation flag. */
  1056.     n = (struct NameChunk *) malloc ((unsigned) CHUNKSIZE);
  1057.     if (n == NULL)
  1058.         quit_cleanup ("Out of memory!\n");
  1059.     NameCurr->Link = n;        /* Link from previous chunk */
  1060.     NameCurr = n;            /* Make the new chunk current. */
  1061.     NameCurr->Link = NULL;        /* Clear forward pointer. */
  1062.     s = (char *) NameCurr;
  1063.     NameLim = s + sizeof (char *);    /* Skip over pointer entry. */
  1064.     }
  1065.     s = NameLim;
  1066.     t = name;
  1067.     while ((*s++ = *t++) != '\0')    /* Store name. */
  1068.     ;
  1069.     t = NameLim;
  1070.     NameLim = s;            /* Update table limit. */
  1071.     return (t);
  1072. }
  1073.  
  1074.  
  1075.  
  1076. int ReadSymTab (label) char label[];
  1077. /* Searches the symbol table for the given label.
  1078.    If not found, points Sym to NULL and returns FALSE.
  1079.    If found, points Sym to the proper table entry,
  1080.      and sets up the following fields:
  1081.     Value    - value of symbol
  1082.     Hunk2    - hunk number in which symbol resides
  1083.            ABSHUNK if value is absolute
  1084.            ones complement of symbol table index if external
  1085.     DefLine2 - statement number in which symbol was defined
  1086.             (NODEF if undefined )
  1087.     If the label is a local label (i.e. the first character is
  1088.     numeric), the current contents of LabLine will be converted
  1089.     to characters and appended to the label before it is searched.
  1090.     (This matches the way AddSymTab added the label to the table.)
  1091.     If the first character of the label is a backslash (i.e. a
  1092.     named local variable) a dollar sign will be appended to the
  1093.     label ahead of the value of LabLine.            */
  1094. {
  1095.     char wlab[MAXLINE], wnum[6];
  1096.     register struct SymTab **hashindex;
  1097.  
  1098.     strcpy (wlab, label);
  1099.     if (((label[0] >= '0') && (label[0] <= '9')) || (label[0] == '\\')) {
  1100.     if (label[0] == '\\')
  1101.         strcat (wlab, "$");
  1102.     sprintf (wnum, "%d", LabLine);    /* If it's a local label, */
  1103.     strcat (wlab, wnum);        /*    append LabLine.     */
  1104.     }
  1105.     hashindex = HashIt (wlab);    /* Get hash index. */
  1106.     Sym = *hashindex;
  1107.     while (Sym != NULL) {
  1108.     if (strcmp (Sym->Nam, wlab) == 0) {
  1109.         Value = Sym->Val;        /* We found it. */
  1110.         Hunk2 = Sym->Hunk;
  1111.         if (!(Sym->Flags & 9))
  1112.         Hunk2 &= 0x0000FFFFL;    /* Isolate hunk number. */
  1113.         DefLine2 = Sym->Defn;
  1114.         return (TRUE);
  1115.     }
  1116.     Sym = Sym->Link;
  1117.     }
  1118.     Value = 0;            /* We didn't find it - */
  1119.     Hunk2 = ABSHUNK;        /*  set value to absolute zero. */
  1120.     DefLine2 = NODEF;
  1121.     return (FALSE);
  1122. }
  1123.  
  1124.  
  1125.  
  1126. struct SymTab **HashIt (label) register char *label;
  1127. /* Returns a pointer to the hash table entry corresponding to "label". */
  1128. {
  1129.     register unsigned i;
  1130.  
  1131.     i = 0;
  1132.     while (*label) {
  1133.     i = ((i << 3) - i + *label++) % HashSize;
  1134.     }
  1135.     return (Hash + i);
  1136. }
  1137.  
  1138.  
  1139.  
  1140. struct SymTab *NextSym (sym) register struct SymTab *sym;
  1141. /* Returns a pointer to the next symbol table entry in memory,
  1142.     or NULL if there are no more symbol table entries.
  1143.     SymChunk and SymChLim must be properly set up.    */
  1144. {
  1145.     register struct SymTab *sp;
  1146.  
  1147.     if (sym == NULL)
  1148.     return (NULL);        /* We're nowhere - get out. */
  1149.     sym++;
  1150.     sp = sym;
  1151.     sp++;
  1152.     if ((SymLim >= SymChunk) && (SymLim <= SymChLim))
  1153.     if (sym >= SymLim)
  1154.         return (NULL);    /* End of symbol table entries */
  1155.     if (sp > SymChLim) {
  1156.     if ((SymChunk = SymChunk->Link) == NULL)
  1157.         return (NULL);    /* End of the last chunk */
  1158.     SymChLim = (struct SymTab *) ((char *) SymChunk + CHUNKSIZE);
  1159.     sym = SymChunk;
  1160.     sym++;            /* First entry in the new chunk */
  1161.     }
  1162.     return (sym);
  1163. }
  1164.  
  1165.  
  1166.  
  1167. AddRef (linenum) int linenum;
  1168. /* Adds "linenum" to the list of references
  1169.     for the symbol pointed to by Sym.    */
  1170. {
  1171.     register int i;
  1172.     register struct Ref *ref, *prevref;
  1173.  
  1174.     if (!Pass2)
  1175.     return;            /* Pass 2 only! */
  1176.     if (!XrefList)
  1177.     return;            /* No cross-reference */
  1178.     prevref = NULL;
  1179.     ref = Sym->Ref1;
  1180.     while (ref) {        /* Chase pointers. */
  1181.     for (i = 0; i < MAXREF; i++) {    /* Scan reference entry */
  1182.         if (ref->RefNum[i] == 0) {    /*  for an empty slot.  */
  1183.         ref->RefNum[i]=linenum;    /* Insert new line number. */
  1184.         return;
  1185.         }
  1186.     }
  1187.     prevref = ref;            /* Remember where we were. */
  1188.     ref = ref->NextRef;        /* Link to the next entry. */
  1189.     }
  1190.     ref = RefLim;            /* Pointer to new entry */
  1191.     RefLim++;                /* Bump limit pointer. */
  1192.     if (((char *) RefLim - (char *) SymCurr) > CHUNKSIZE) {
  1193.     ref = (struct Ref *) malloc ((unsigned) CHUNKSIZE);
  1194.     if (ref == NULL) {
  1195.         fprintf (stderr, "     \nOut of memory");
  1196.         fprintf (stderr, " - cross-reference disabled.\n");
  1197.         XrefList = FALSE;
  1198.         return;
  1199.     }
  1200.     SymCurr->Link = (struct SymTab *) ref;    /* Link from prev. chunk */
  1201.     SymCurr = (struct SymTab *)ref;    /* Make the new chunk current. */
  1202.     SymCurr->Link = NULL;        /* Clear forward pointer. */
  1203.     ref++;                /* Skip over pointer entry. */
  1204.     RefLim = ref;            /* New table limit */
  1205.     RefLim++;            /* Bump it. */
  1206.     }
  1207.     ref->NextRef = NULL;        /* Pointer to next entry */
  1208.     ref->RefNum[0] = linenum;        /* First reference in new entry */
  1209.     for (i = 1; i < MAXREF; i++)
  1210.     ref->RefNum[i] = 0;        /* Clear remaining slots. */
  1211.     if (prevref == NULL)
  1212.     Sym->Ref1 = ref;        /* Link to first entry */
  1213.     else
  1214.     prevref->NextRef = ref;        /* Link to next entry */
  1215. }
  1216.  
  1217.  
  1218.  
  1219. int CountNest (s) register char *s;
  1220. /* Returns 1 if "s" contains any IF statement (i.e. IFEQ, etc.).
  1221.    Returns -1 if "s" contains "ENDC" or "ENDIF".
  1222.    Returns 0 in all other cases.        */
  1223. {
  1224.    if (strcmp (s, "ENDC") == 0)
  1225.     return (-1);
  1226.    else if (strcmp (s, "ENDIF") == 0)
  1227.     return (-1);
  1228.    else if (*s++ != 'I')
  1229.     return (0);
  1230.    else if (*s++ != 'F')
  1231.     return (0);
  1232.    else if (strcmp (s, "EQ") == 0)
  1233.     return (1);
  1234.    else if (strcmp (s, "NE") == 0)
  1235.     return (1);
  1236.    else if (strcmp (s, "GT") == 0)
  1237.     return (1);
  1238.    else if (strcmp (s, "GE") == 0)
  1239.     return (1);
  1240.    else if (strcmp (s, "LT") == 0)
  1241.     return (1);
  1242.    else if (strcmp (s, "LE") == 0)
  1243.     return (1);
  1244.    else if (strcmp (s, "C" ) == 0)
  1245.     return (1);
  1246.    else if (strcmp (s, "NC") == 0)
  1247.     return (1);
  1248.    else if (strcmp (s, "D" ) == 0)
  1249.     return (1);
  1250.    else if (strcmp (s, "ND") == 0)
  1251.     return (1);
  1252.    else
  1253.     return (0);
  1254. }
  1255.  
  1256.  
  1257.  
  1258. Heap2Space (n) int n;
  1259. /* Die if we can't find "n" bytes on the secondary heap. */
  1260. {
  1261.     if ((NextFNS + n) > (char *) InF) {
  1262.     printf ("\n%5d   %s\n", LineCount, Line);
  1263.     quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
  1264.     }
  1265. }
  1266.  
  1267.  
  1268.  
  1269. ParseSpace (n) int n;
  1270. /* Special version of Heap2Space for the expression parser */
  1271. {
  1272.     if (((char *) Term + n) > (char *) Ops) {
  1273.     printf ("\n%5d   %s\n", LineCount, Line);
  1274.     quit_cleanup ("Secondary heap overflow - assembly terminated.\n");
  1275.     }
  1276. }
  1277.